Виктория Карпейкина, Юлия Щучкина, Максим Бочаров

Тема проекта: "Классификация криптовалют на основе их рыночных показателей".

EDA и Визуализация

In [1]:
import numpy as np
import pandas as pd
import scipy.stats as sts

import matplotlib.pyplot as plt
%config InlineBackend.figure_format = 'retina'

import seaborn as sns
sns.set_style('whitegrid')
sns.set_palette('Paired')

import plotly.express as px
In [2]:
# Распечатали табличку с котировками
df = pd.read_csv('df_price.csv')
df.head()
Out[2]:
Unnamed: 0 BTCUSDT ETHUSDT BNBUSDT NEOUSDT LTCUSDT QTUMUSDT ADAUSDT XRPUSDT EOSUSDT ... NKNUSDT STXUSDT KAVAUSDT ARPAUSDT IOTXUSDT RLCUSDT CTXCUSDT BCHUSDT TROYUSDT VITEUSDT
0 0 7200.85 130.77 13.7184 8.850 41.62 1.603 0.03348 0.19305 2.6039 ... 0.01809 0.0989 1.1364 0.01064 0.003457 0.4177 0.0640 204.44 0.006779 0.01104
1 1 6965.71 127.19 13.0105 8.462 39.43 1.533 0.03269 0.18750 2.4593 ... 0.01845 0.0897 1.0172 0.00985 0.003358 0.3764 0.0614 195.49 0.006475 0.01042
2 2 7344.96 134.35 13.6474 8.888 42.23 1.629 0.03417 0.19338 2.6396 ... 0.01820 0.0945 1.0241 0.01007 0.003410 0.4041 0.0633 222.43 0.006432 0.01123
3 3 7354.11 134.20 13.8092 9.077 42.78 1.642 0.03434 0.19305 2.6481 ... 0.01785 0.0944 1.0401 0.01022 0.003543 0.3981 0.0698 224.47 0.006401 0.01170
4 4 7358.75 135.37 14.0532 9.020 43.30 1.631 0.03460 0.19453 2.6865 ... 0.01868 0.0920 1.0310 0.01008 0.003565 0.4050 0.0668 222.79 0.006568 0.01109

5 rows × 69 columns

In [3]:
df.shape
Out[3]:
(1226, 69)

По столбцам: валютные пары типа «криптовалюта/USDT». По строкам: их ежедневные цены начиная с 1.01.2020 и до 10.05.2023.

In [4]:
df.rename(columns={'Unnamed: 0':'Date'}, inplace=True)
df.head()
Out[4]:
Date BTCUSDT ETHUSDT BNBUSDT NEOUSDT LTCUSDT QTUMUSDT ADAUSDT XRPUSDT EOSUSDT ... NKNUSDT STXUSDT KAVAUSDT ARPAUSDT IOTXUSDT RLCUSDT CTXCUSDT BCHUSDT TROYUSDT VITEUSDT
0 0 7200.85 130.77 13.7184 8.850 41.62 1.603 0.03348 0.19305 2.6039 ... 0.01809 0.0989 1.1364 0.01064 0.003457 0.4177 0.0640 204.44 0.006779 0.01104
1 1 6965.71 127.19 13.0105 8.462 39.43 1.533 0.03269 0.18750 2.4593 ... 0.01845 0.0897 1.0172 0.00985 0.003358 0.3764 0.0614 195.49 0.006475 0.01042
2 2 7344.96 134.35 13.6474 8.888 42.23 1.629 0.03417 0.19338 2.6396 ... 0.01820 0.0945 1.0241 0.01007 0.003410 0.4041 0.0633 222.43 0.006432 0.01123
3 3 7354.11 134.20 13.8092 9.077 42.78 1.642 0.03434 0.19305 2.6481 ... 0.01785 0.0944 1.0401 0.01022 0.003543 0.3981 0.0698 224.47 0.006401 0.01170
4 4 7358.75 135.37 14.0532 9.020 43.30 1.631 0.03460 0.19453 2.6865 ... 0.01868 0.0920 1.0310 0.01008 0.003565 0.4050 0.0668 222.79 0.006568 0.01109

5 rows × 69 columns

Запишем дату каждого наблюдения в таблицу

In [5]:
pd.date_range(start='1/1/2020', periods=1226)
Out[5]:
DatetimeIndex(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04',
               '2020-01-05', '2020-01-06', '2020-01-07', '2020-01-08',
               '2020-01-09', '2020-01-10',
               ...
               '2023-05-01', '2023-05-02', '2023-05-03', '2023-05-04',
               '2023-05-05', '2023-05-06', '2023-05-07', '2023-05-08',
               '2023-05-09', '2023-05-10'],
              dtype='datetime64[ns]', length=1226, freq='D')
In [6]:
df['Date'] = pd.date_range(start='1/1/2020', periods=1226)
df.head()
Out[6]:
Date BTCUSDT ETHUSDT BNBUSDT NEOUSDT LTCUSDT QTUMUSDT ADAUSDT XRPUSDT EOSUSDT ... NKNUSDT STXUSDT KAVAUSDT ARPAUSDT IOTXUSDT RLCUSDT CTXCUSDT BCHUSDT TROYUSDT VITEUSDT
0 2020-01-01 7200.85 130.77 13.7184 8.850 41.62 1.603 0.03348 0.19305 2.6039 ... 0.01809 0.0989 1.1364 0.01064 0.003457 0.4177 0.0640 204.44 0.006779 0.01104
1 2020-01-02 6965.71 127.19 13.0105 8.462 39.43 1.533 0.03269 0.18750 2.4593 ... 0.01845 0.0897 1.0172 0.00985 0.003358 0.3764 0.0614 195.49 0.006475 0.01042
2 2020-01-03 7344.96 134.35 13.6474 8.888 42.23 1.629 0.03417 0.19338 2.6396 ... 0.01820 0.0945 1.0241 0.01007 0.003410 0.4041 0.0633 222.43 0.006432 0.01123
3 2020-01-04 7354.11 134.20 13.8092 9.077 42.78 1.642 0.03434 0.19305 2.6481 ... 0.01785 0.0944 1.0401 0.01022 0.003543 0.3981 0.0698 224.47 0.006401 0.01170
4 2020-01-05 7358.75 135.37 14.0532 9.020 43.30 1.631 0.03460 0.19453 2.6865 ... 0.01868 0.0920 1.0310 0.01008 0.003565 0.4050 0.0668 222.79 0.006568 0.01109

5 rows × 69 columns

In [7]:
df.tail()
Out[7]:
Date BTCUSDT ETHUSDT BNBUSDT NEOUSDT LTCUSDT QTUMUSDT ADAUSDT XRPUSDT EOSUSDT ... NKNUSDT STXUSDT KAVAUSDT ARPAUSDT IOTXUSDT RLCUSDT CTXCUSDT BCHUSDT TROYUSDT VITEUSDT
1221 2023-05-06 28848.20 1896.33 321.9 10.01 83.26 2.777 0.3787 0.4582 0.983 ... 0.1065 0.7000 0.724 0.03957 0.02357 1.805 0.1812 117.0 0.002933 0.01993
1222 2023-05-07 28430.10 1870.40 321.0 9.88 83.42 2.717 0.3760 0.4490 0.969 ... 0.1056 0.7314 0.726 0.04270 0.02331 1.760 0.1802 116.1 0.002890 0.01976
1223 2023-05-08 27668.79 1847.56 313.8 9.13 77.71 2.575 0.3653 0.4283 0.906 ... 0.0922 0.7410 0.745 0.03921 0.02226 1.675 0.1646 111.1 0.002628 0.01716
1224 2023-05-09 27628.27 1846.52 312.1 9.26 79.90 2.610 0.3633 0.4289 0.919 ... 0.0953 0.6918 0.802 0.03930 0.02229 1.539 0.1673 122.2 0.002627 0.01745
1225 2023-05-10 27598.75 1840.84 314.3 9.64 80.93 2.642 0.3693 0.4303 0.913 ... 0.0972 0.6634 0.887 0.04453 0.02278 1.577 0.1653 115.8 0.002680 0.01802

5 rows × 69 columns

Сделаем Дату индексом таблицы

In [8]:
df.set_index('Date', inplace=True)
df.head()
Out[8]:
BTCUSDT ETHUSDT BNBUSDT NEOUSDT LTCUSDT QTUMUSDT ADAUSDT XRPUSDT EOSUSDT IOTAUSDT ... NKNUSDT STXUSDT KAVAUSDT ARPAUSDT IOTXUSDT RLCUSDT CTXCUSDT BCHUSDT TROYUSDT VITEUSDT
Date
2020-01-01 7200.85 130.77 13.7184 8.850 41.62 1.603 0.03348 0.19305 2.6039 0.1606 ... 0.01809 0.0989 1.1364 0.01064 0.003457 0.4177 0.0640 204.44 0.006779 0.01104
2020-01-02 6965.71 127.19 13.0105 8.462 39.43 1.533 0.03269 0.18750 2.4593 0.1584 ... 0.01845 0.0897 1.0172 0.00985 0.003358 0.3764 0.0614 195.49 0.006475 0.01042
2020-01-03 7344.96 134.35 13.6474 8.888 42.23 1.629 0.03417 0.19338 2.6396 0.1664 ... 0.01820 0.0945 1.0241 0.01007 0.003410 0.4041 0.0633 222.43 0.006432 0.01123
2020-01-04 7354.11 134.20 13.8092 9.077 42.78 1.642 0.03434 0.19305 2.6481 0.1734 ... 0.01785 0.0944 1.0401 0.01022 0.003543 0.3981 0.0698 224.47 0.006401 0.01170
2020-01-05 7358.75 135.37 14.0532 9.020 43.30 1.631 0.03460 0.19453 2.6865 0.1718 ... 0.01868 0.0920 1.0310 0.01008 0.003565 0.4050 0.0668 222.79 0.006568 0.01109

5 rows × 68 columns

Типы данных

Теперь посмотри на другие типы данных

In [9]:
df.dtypes
Out[9]:
BTCUSDT     float64
ETHUSDT     float64
BNBUSDT     float64
NEOUSDT     float64
LTCUSDT     float64
             ...   
RLCUSDT     float64
CTXCUSDT    float64
BCHUSDT     float64
TROYUSDT    float64
VITEUSDT    float64
Length: 68, dtype: object

В данной таблице все переменные числовые, т.к. это цены, тип перменных float64 задан правильно

In [10]:
df.info()
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 1226 entries, 2020-01-01 to 2023-05-10
Data columns (total 68 columns):
 #   Column     Non-Null Count  Dtype  
---  ------     --------------  -----  
 0   BTCUSDT    1226 non-null   float64
 1   ETHUSDT    1226 non-null   float64
 2   BNBUSDT    1226 non-null   float64
 3   NEOUSDT    1226 non-null   float64
 4   LTCUSDT    1226 non-null   float64
 5   QTUMUSDT   1226 non-null   float64
 6   ADAUSDT    1226 non-null   float64
 7   XRPUSDT    1226 non-null   float64
 8   EOSUSDT    1226 non-null   float64
 9   IOTAUSDT   1226 non-null   float64
 10  XLMUSDT    1226 non-null   float64
 11  ONTUSDT    1226 non-null   float64
 12  TRXUSDT    1226 non-null   float64
 13  ETCUSDT    1226 non-null   float64
 14  ICXUSDT    1226 non-null   float64
 15  NULSUSDT   1226 non-null   float64
 16  VETUSDT    1226 non-null   float64
 17  LINKUSDT   1226 non-null   float64
 18  WAVESUSDT  1226 non-null   float64
 19  ONGUSDT    1226 non-null   float64
 20  HOTUSDT    1226 non-null   float64
 21  ZILUSDT    1226 non-null   float64
 22  ZRXUSDT    1226 non-null   float64
 23  FETUSDT    1226 non-null   float64
 24  BATUSDT    1226 non-null   float64
 25  XMRUSDT    1226 non-null   float64
 26  ZECUSDT    1226 non-null   float64
 27  IOSTUSDT   1226 non-null   float64
 28  CELRUSDT   1226 non-null   float64
 29  DASHUSDT   1226 non-null   float64
 30  OMGUSDT    1226 non-null   float64
 31  THETAUSDT  1226 non-null   float64
 32  ENJUSDT    1226 non-null   float64
 33  MATICUSDT  1226 non-null   float64
 34  ATOMUSDT   1226 non-null   float64
 35  TFUELUSDT  1226 non-null   float64
 36  ONEUSDT    1226 non-null   float64
 37  FTMUSDT    1226 non-null   float64
 38  ALGOUSDT   1226 non-null   float64
 39  DOGEUSDT   1226 non-null   float64
 40  DUSKUSDT   1226 non-null   float64
 41  ANKRUSDT   1226 non-null   float64
 42  WINUSDT    1226 non-null   float64
 43  COSUSDT    1226 non-null   float64
 44  MTLUSDT    1226 non-null   float64
 45  TOMOUSDT   1226 non-null   float64
 46  PERLUSDT   1226 non-null   float64
 47  DENTUSDT   1226 non-null   float64
 48  DOCKUSDT   1226 non-null   float64
 49  WANUSDT    1226 non-null   float64
 50  FUNUSDT    1226 non-null   float64
 51  CHZUSDT    1226 non-null   float64
 52  BANDUSDT   1226 non-null   float64
 53  BUSDUSDT   1226 non-null   float64
 54  XTZUSDT    1226 non-null   float64
 55  RENUSDT    1226 non-null   float64
 56  RVNUSDT    1226 non-null   float64
 57  HBARUSDT   1226 non-null   float64
 58  NKNUSDT    1226 non-null   float64
 59  STXUSDT    1226 non-null   float64
 60  KAVAUSDT   1226 non-null   float64
 61  ARPAUSDT   1226 non-null   float64
 62  IOTXUSDT   1226 non-null   float64
 63  RLCUSDT    1226 non-null   float64
 64  CTXCUSDT   1226 non-null   float64
 65  BCHUSDT    1226 non-null   float64
 66  TROYUSDT   1226 non-null   float64
 67  VITEUSDT   1226 non-null   float64
dtypes: float64(68)
memory usage: 660.9 KB

Пропуски

Проверим, есть ли в данных пропуски

In [11]:
df[df.isnull().sum(axis=1) != 0]
Out[11]:
BTCUSDT ETHUSDT BNBUSDT NEOUSDT LTCUSDT QTUMUSDT ADAUSDT XRPUSDT EOSUSDT IOTAUSDT ... NKNUSDT STXUSDT KAVAUSDT ARPAUSDT IOTXUSDT RLCUSDT CTXCUSDT BCHUSDT TROYUSDT VITEUSDT
Date

0 rows × 68 columns

Пропусков в данных нет

Визуализация

Теперь возьмем 5 основых криптовалют (BTCUSDT, ETHUSDT, BNBUSDT, NEOUSDT, LTCUSDT - на Бинансе это 5 первых) для первой картинки, и те же криптовалюты, но без биткоина, для второй картинки и построим для них визуализацию динамики цен и гистограммы.

Ответим на вопросы: Что происходило с финансовыми рынками в течение последних 2,5 лет? Они росли? Они падали? Видно ли, что были кризисы? Распределение стоимости криптовалют похоже на нормальное?

In [12]:
tickers = ['BTCUSDT','ETHUSDT', 'BNBUSDT', 'NEOUSDT', 'LTCUSDT']
tickers_without_bitcoin = ['ETHUSDT', 'BNBUSDT', 'NEOUSDT', 'LTCUSDT']
mean_prices = df.mean(axis=1)
In [13]:
# С учетом биткойна
fig, ax = plt.subplots(figsize=(13, 7))
ax.plot(df.index, df[tickers], label=tickers)   
ax.plot(df.index, mean_prices, label='Среднее по рынку',
        c='black', lw=2, ls='--')
ax.set_title('Изменения цен 5 основных тикеров с 2020 года')
ax.set_xlabel('Год')
ax.set_ylabel('Цена')
ax.legend()
plt.show()
In [14]:
# Без учета биткойна
fig, ax = plt.subplots(figsize=(13, 7))
ax.plot(df.index, df[tickers_without_bitcoin], label=tickers_without_bitcoin)   
ax.plot(df.index, mean_prices, label='Среднее по рынку', 
        c='black', lw=2, ls='--')
ax.set_title('Изменения цен основных тикеров (не включая биткоин) с 2020 года')
ax.set_xlabel('Год')
ax.set_ylabel('Цена')
ax.legend()
plt.show()

Сравнив 2 полученные картинки, заметно, что котировки биткоина намного более масштабны по сравнению с другими рассмотренными криптовалютами, что во многом объясняется разнообразием сфер его применения, широчайшей всемирной известностью и популярностью среди неквалифицированных инвесторов.

Однако общие тенденции динамики цен биткоина и других рассмотренных криптовалют сохраняются.

Вывод

В течение последних 3 динамика рынка криптовалют была довольно неодназначной. Однако можно сказать, что с начала 2020 года к маю 2023 года цены криптовалют выросли (хорошо видно на примере 3 из 5 рассмотренных криптовалют: BTC, ETH, BNB).

Сперва можно наблюдать довольно успешное восстановление крипторынка после пандемии covid-19 в 2020 году. Затем можно наблюдать значительный спад в конце весны 2021 года, связанный с тем, что: биткоин обвалился более чем на 30% до 30 тысяч, т.к. Илон Маск отказался принимать платежи в виде биткоина в Tesla - отчасти из-за запретов на цифровые активы в Китае и того, что их майнинг вредит окружающей среде, а эфир стал стоить менее $2000, упав на 44%, из-за этого, прикрываясь разными причинами, криптобиржи временно приостанавливали покупку и вывод средств. Далее значимый кризис наблюдался в начале 2022 года, по причине напряженной политической обстановки в Казахстане и началом СВО. Следующий кризис, наблюдаемиый весной 2022, стали называть системным из-за падения доверия инвесторов к крипторынку на фоне скандала вокруг биржи FTX — четвертой среди крупнейших бирж по торговле криптовалютами, связанного с недостаточным риск-менеджментом, что в период борьбы с инфляцией в Америке и повышением ключевой ставки сильно сказалось на котировках криптовалют.

Все эти кризисы отразились на графиках динамики цен рассмотренных криптовалют как резкие скачки в сторону понижения их цен.

plotly.express

Для более удобного и наглядного представления данных построим те же графики в plotly.express

In [15]:
import plotly.graph_objects as go
In [16]:
fig = px.line(
    df,
    x = df.index,
    y = ['BTCUSDT','ETHUSDT', 'BNBUSDT','NEOUSDT', 'LTCUSDT'],
    title ='Изменение цены 5 основных криптовалют с 2020 года'
)
trace = go.Scatter(x=df.index, y = mean_prices, name = 'mean')
fig.add_trace(trace)

fig.show()
In [17]:
fig = px.line(
    df,
    x = df.index,
    y = ['ETHUSDT', 'BNBUSDT','NEOUSDT', 'LTCUSDT'],
    title ='Изменение цены основных криптовалют (без биткоина) с 2020 года'
)
trace = go.Scatter(x = df.index, y = mean_prices, name = 'mean') 
fig.add_trace(trace)

fig.show()
In [18]:
# Строим гистограммы цен
from itertools import combinations
axs = sorted(list(combinations([0, 1, 2], 2)) +
             list(zip([0, 1, 2], [0, 1, 2])))[:-1]
In [19]:
fig, ax = plt.subplots(2, 3, figsize=(15, 12))
for i in axs:
    ind = axs.index(i)
    ax[i].hist(df[tickers[ind]])
    ax[i].set_title(f'Гистограмма цен {tickers[ind]}')
    ax[i].set_xlabel(f'Цена')
    ax[i].set_ylabel(f'Частота')
    
ax[(1, 0)].axis('off')
plt.show()

Распределение цен криптовалют не похоже на нормальное.

Нормирование данных. Логарифмирование

Для того чтобы более наглядно визуализировать динамику цен криптовалют, можно рассмотерть логарифмы цен, что позволит сгладить различия между биткоином и другими тикерами.

In [20]:
# Логарифмируем цены криптовалют
from math import log

df_log = pd.DataFrame()
df_log = df.copy()

col = df_log.columns.values.tolist()

for item in col:
    df_log[item] = df_log[item].apply(log)

df_log
Out[20]:
BTCUSDT ETHUSDT BNBUSDT NEOUSDT LTCUSDT QTUMUSDT ADAUSDT XRPUSDT EOSUSDT IOTAUSDT ... NKNUSDT STXUSDT KAVAUSDT ARPAUSDT IOTXUSDT RLCUSDT CTXCUSDT BCHUSDT TROYUSDT VITEUSDT
Date
2020-01-01 8.881954 4.873440 2.618738 2.180417 3.728581 0.471877 -3.396807 -1.644806 0.957010 -1.828838 ... -4.012396 -2.313646 0.127865 -4.543135 -5.667354 -0.872992 -2.748872 5.320275 -4.993970 -4.506230
2020-01-02 8.848755 4.845682 2.565757 2.135586 3.674527 0.427227 -3.420686 -1.673976 0.899877 -1.842632 ... -3.992691 -2.411285 0.017054 -4.620284 -5.696410 -0.977103 -2.790345 5.275509 -5.039791 -4.564028
2020-01-03 8.901770 4.900448 2.613549 2.184702 3.743131 0.487966 -3.376407 -1.643098 0.970627 -1.793361 ... -4.006334 -2.359155 0.023814 -4.598195 -5.681043 -0.906093 -2.759870 5.404612 -5.046454 -4.489167
2020-01-04 8.903015 4.899331 2.625335 2.205744 3.756071 0.495915 -3.371444 -1.644806 0.973842 -1.752154 ... -4.025752 -2.360214 0.039317 -4.583409 -5.642781 -0.921052 -2.662121 5.413742 -5.051301 -4.448166
2020-01-05 8.903645 4.908012 2.642850 2.199444 3.768153 0.489193 -3.363902 -1.637169 0.988239 -1.761424 ... -3.980302 -2.385967 0.030529 -4.597202 -5.636591 -0.903868 -2.706052 5.406230 -5.025485 -4.501711
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
2023-05-06 10.269803 7.547676 5.774241 2.303585 4.421968 1.021371 -0.971011 -0.780450 -0.017146 -1.649739 ... -2.239610 -0.356675 -0.322964 -3.229684 -3.747781 0.590561 -1.708154 4.762174 -5.831729 -3.915529
2023-05-07 10.255204 7.533908 5.771441 2.290513 4.423888 0.999528 -0.978166 -0.800732 -0.031491 -1.651302 ... -2.248097 -0.312795 -0.320205 -3.153556 -3.758873 0.565314 -1.713688 4.754452 -5.846499 -3.924096
2023-05-08 10.228060 7.521621 5.748756 2.211566 4.352984 0.945850 -1.007036 -0.847931 -0.098716 -1.713133 ... -2.383795 -0.299755 -0.294371 -3.238823 -3.804964 0.515813 -1.804237 4.710431 -5.941532 -4.065174
2023-05-09 10.226595 7.521058 5.743324 2.225704 4.380776 0.959350 -1.012526 -0.846531 -0.084469 -1.717023 ... -2.350725 -0.368458 -0.220647 -3.236531 -3.803617 0.431133 -1.787967 4.805659 -5.941913 -4.048416
2023-05-10 10.225526 7.517977 5.750348 2.265921 4.393585 0.971536 -0.996146 -0.843273 -0.091019 -1.714243 ... -2.330985 -0.410377 -0.119910 -3.111592 -3.781872 0.455524 -1.799993 4.751865 -5.921938 -4.016273

1226 rows × 68 columns

In [21]:
tickers = ['BTCUSDT','ETHUSDT', 'BNBUSDT', 'NEOUSDT', 'LTCUSDT']
mean_prices_log = df_log.mean(axis=1)
In [22]:
# Динамика логарифмов цен 
fig, ax = plt.subplots(figsize=(13, 7))
ax.plot(df_log.index, df_log[tickers], label=tickers)   
ax.plot(df_log.index, mean_prices_log, label='Среднее по рынку',
        c='black', lw=2, ls='--')
ax.set_title('Изменения логарифмов цен 5 основных тикеров с 2020 года')
ax.set_xlabel('Год')
ax.set_ylabel('Цена')
ax.legend()
plt.show()

На данном графике динамика цен биткоина уже не настолько масштабна по сравнению с прочими рассмотренными криптовалютами.

In [23]:
# Гистограммы логарифмов цен
fig, ax = plt.subplots(2, 3, figsize=(15, 12))
for i in axs:
    ind = axs.index(i)
    ax[i].hist(df_log[tickers[ind]])
    ax[i].set_title(f'Гистограмма цен {tickers[ind]}')
    ax[i].set_xlabel(f'Цена')
    ax[i].set_ylabel(f'Частота')
    
ax[(1, 0)].axis('off')
plt.show()

Распределение цен криптовалют не похоже на нормальное.

Доходность

Рассмотрение рыночных показателей криптовалют начнем с доходности

Доходность – это процентное изменение стоимости за некоторый промежуток времени. Мы будем работать с доходностями за день:

$$ R_t = \frac{P_t - P_{t-1}}{P_{t-1}} $$

Посчитаем разность между каждой строкой таблицы и предыдущей строкой, используя команду .diff(). Чтобы сдвинуть все строки на одну вниз, используем команду shift(1).

Поделим результат работы команды diff на результат работы команды shift. В первой колонке теперь все значения NaN, так как мы не можем посчитать доходность для самого первого дня. Удалим из таблицы эту строку.

In [24]:
diff = df.diff()
shift = df.shift(1)
df_r = (diff / shift)
df_r.drop(index=df_r.index[0], inplace=True)
df_r.head()
Out[24]:
BTCUSDT ETHUSDT BNBUSDT NEOUSDT LTCUSDT QTUMUSDT ADAUSDT XRPUSDT EOSUSDT IOTAUSDT ... NKNUSDT STXUSDT KAVAUSDT ARPAUSDT IOTXUSDT RLCUSDT CTXCUSDT BCHUSDT TROYUSDT VITEUSDT
Date
2020-01-02 -0.032654 -0.027376 -0.051602 -0.043842 -0.052619 -0.043668 -0.023596 -0.028749 -0.055532 -0.013699 ... 0.019900 -0.093023 -0.104893 -0.074248 -0.028638 -0.098875 -0.040625 -0.043778 -0.044787 -0.056159
2020-01-03 0.054445 0.056294 0.048953 0.050343 0.071012 0.062622 0.045274 0.031360 0.073314 0.050505 ... -0.013550 0.053512 0.006783 0.022335 0.015485 0.073592 0.030945 0.137808 -0.006641 0.077735
2020-01-04 0.001246 -0.001116 0.011856 0.021265 0.013024 0.007980 0.004975 -0.001706 0.003220 0.042067 ... -0.019231 -0.001058 0.015623 0.014896 0.039003 -0.014848 0.102686 0.009171 -0.004835 0.041852
2020-01-05 0.000631 0.008718 0.017669 -0.006280 0.012155 -0.006699 0.007571 0.007666 0.014501 -0.009227 ... 0.046499 -0.025424 -0.008749 -0.013699 0.006209 0.017332 -0.042980 -0.007484 0.026152 -0.052137
2020-01-06 0.054255 0.064859 0.063608 0.081707 0.057737 0.071122 0.078613 0.146867 0.061083 0.062864 ... -0.016595 0.044565 0.021242 -0.008929 0.056662 -0.024444 0.007485 0.096324 -0.018909 0.031560

5 rows × 68 columns

Визуализация

Теперь возьмем 5 основых криптовалют (BTCUSDT, ETHUSDT, BNBUSDT, NEOUSDT, LTCUSDT - на Бинансе это 5 первых) и построим для них визуализацию динамики доходностей, гистограммы и ящики с усами.

In [25]:
# Динамика доходностей
fig, ax = plt.subplots(2, 3, figsize=(25, 12))
for i in axs:
    ind = axs.index(i)
    ax[i].plot(df_r[tickers[ind]])
    ax[i].set_title(f'Динамика доходностей {tickers[ind]}')
    ax[i].set_xlabel(f'Месяц')
    ax[i].set_ylabel(f'Доходность криптовалюты')
    
ax[(1, 0)].axis('off')
plt.show()
In [26]:
# Гистограммы
fig, ax = plt.subplots(2, 3, figsize=(15, 12))
for i in axs:
    ind = axs.index(i)
    ax[i].hist(df_r[tickers[ind]])
    ax[i].set_title(f'Гистограмма доходностей {tickers[ind]}')
    ax[i].set_xlabel(f'Доходность криптовалюты')
    ax[i].set_ylabel(f'Частота')
    
ax[(1, 0)].axis('off')
plt.show()

Доходность рассмотренных криптовалют похожа на нормальное распределение.

In [27]:
# Ящики с усами
fig, ax = plt.subplots(2, 3, figsize=(16, 12))
for i in axs:
    ind = axs.index(i)
    ax[i].boxplot(df_r[tickers[ind]].dropna())
    ax[i].set_title(f'Распределение доходностей {tickers[ind]}')
    ax[i].get_xaxis().set_visible(False)
    
ax[(1, 0)].axis('off')
plt.show()

По ящику с усами для рассмотренных криптовалют видно, что в данных имеются выбросы, однако для боллее корректного анализа доходностей их исключать не нужно.

Чтобы посмотреть, насколько сильно распределение отличается от нормального, можно вспользоваться диаграммой квантиль-квантиль. Построим ее на примере для биткоина. На картинке ниже видно, что центр распределения похож на нормальное, а квантили на хвостах отличаются от нормальных в более тяжёлую сторону:

In [28]:
ax = plt.subplot(111)
x = df_r['BTCUSDT'].values
sts.probplot(x, dist='norm', sparams=(x.mean(), x.std()), plot=ax);

Накопленная доходность

При анализе финансовых активов также используют такой показатель, как накопленная доходность. Рассчитаем и визуализируем ее для наших криптовалют.

In [29]:
df_r_nakop = pd.DataFrame()

df_r_nakop = df_r
df_r_nakop = df_r_nakop.cumsum(axis=None)
df_r_nakop
Out[29]:
BTCUSDT ETHUSDT BNBUSDT NEOUSDT LTCUSDT QTUMUSDT ADAUSDT XRPUSDT EOSUSDT IOTAUSDT ... NKNUSDT STXUSDT KAVAUSDT ARPAUSDT IOTXUSDT RLCUSDT CTXCUSDT BCHUSDT TROYUSDT VITEUSDT
Date
2020-01-02 -0.032654 -0.027376 -0.051602 -0.043842 -0.052619 -0.043668 -0.023596 -0.028749 -0.055532 -0.013699 ... 0.019900 -0.093023 -0.104893 -0.074248 -0.028638 -0.098875 -0.040625 -0.043778 -0.044787 -0.056159
2020-01-03 0.021791 0.028917 -0.002649 0.006501 0.018393 0.018954 0.021678 0.002611 0.017781 0.036806 ... 0.006350 -0.039512 -0.098109 -0.051913 -0.013152 -0.025283 -0.009680 0.094029 -0.051428 0.021576
2020-01-04 0.023037 0.027801 0.009206 0.027766 0.031417 0.026935 0.026653 0.000904 0.021002 0.078874 ... -0.012880 -0.040570 -0.082486 -0.037017 0.025851 -0.040131 0.093005 0.103201 -0.056263 0.063428
2020-01-05 0.023667 0.036519 0.026876 0.021486 0.043572 0.020235 0.034224 0.008571 0.035503 0.069647 ... 0.033618 -0.065993 -0.091235 -0.050716 0.032060 -0.022798 0.050025 0.095717 -0.030111 0.011291
2020-01-06 0.077923 0.101379 0.090484 0.103193 0.101309 0.091357 0.112837 0.155438 0.096586 0.132510 ... 0.017023 -0.021428 -0.069993 -0.059645 0.088722 -0.047243 0.057510 0.192040 -0.049020 0.042851
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
2023-05-06 2.282918 4.230013 4.979430 2.288472 2.423518 3.241932 4.454197 3.148163 1.229790 2.376917 ... 6.291018 5.509932 2.729834 5.097200 6.213899 5.477371 6.186730 1.374650 2.749509 4.286102
2023-05-07 2.268425 4.216339 4.976634 2.275485 2.425439 3.220326 4.447068 3.128085 1.215548 2.375355 ... 6.282567 5.554789 2.732597 5.176300 6.202868 5.452440 6.181212 1.366957 2.734848 4.277572
2023-05-08 2.241646 4.204128 4.954204 2.199574 2.356991 3.168062 4.418610 3.081982 1.150532 2.315397 ... 6.155674 5.567915 2.758768 5.094567 6.157823 5.404145 6.094641 1.323891 2.644191 4.145993
2023-05-09 2.240182 4.203565 4.948787 2.213812 2.385172 3.181654 4.413135 3.083383 1.164881 2.311514 ... 6.189296 5.501518 2.835278 5.096862 6.159171 5.322951 6.111045 1.423801 2.643810 4.162893
2023-05-10 2.239113 4.200489 4.955836 2.254849 2.398064 3.193915 4.429650 3.086648 1.158352 2.314298 ... 6.209233 5.460466 2.941263 5.229941 6.181154 5.347642 6.099090 1.371428 2.663985 4.195557

1225 rows × 68 columns

In [30]:
# Динамика накопленных доходностей
fig, ax = plt.subplots(2, 3, figsize=(25, 12))
for i in axs:
    ind = axs.index(i)
    ax[i].plot(df_r_nakop[tickers[ind]])
    ax[i].set_title(f'Динамика доходностей {tickers[ind]}')
    ax[i].set_xlabel(f'Месяц')
    ax[i].set_ylabel(f'Доходность криптовалюты')
    
ax[(1, 0)].axis('off')
plt.show()

По графикам видно, что в целом с 2020 года накопленная доходность криптовалют росла и на 10.05.2023 она была положительна. Наибольшей накопленной доходностью по состоянию на 10.05.2023 обладал BNB.

Дальнейший ход работы

Далее в рамках нашего проекта мы планируем рассчитать следующие рыночные показатели криптовалют:

  • Value at Risk (VaR)
  • Волатильность
  • Коэффициент Шарпа

Затем на основе этих показателей обучить модель Кластеризации, и с ее помощью разделить на группы проанализированные криптовалюты.